package pl.edu.agh.mguesser.game;

import pl.edu.agh.mguesser.game.answer.Answer;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import pl.edu.agh.mguesser.game.answer.AnswerRequiredHandler;
import pl.edu.agh.mguesser.game.answer.AnswerRequiredHandlerFactory;
import pl.edu.agh.mguesser.game.listener.*;
import pl.edu.agh.mguesser.game.stats.ScoreContainer;
import pl.edu.agh.mguesser.game.stats.ScoreContainerFactory;
import pl.edu.agh.mguesser.game.stats.SimpleScoreContainerFactory;
import pl.edu.agh.mguesser.game.stop.SimpleStopRequestHandlerFactory;
import pl.edu.agh.mguesser.game.stop.StopRequestHandler;
import pl.edu.agh.mguesser.game.stop.StopRequestHandlerFactory;
import pl.edu.agh.mguesser.metadata.MetadataProvider;
import pl.edu.agh.mguesser.player.Player;

/**
 * Every subclass needs to be a Spring component.
 *
 * @author keiran
 */
public abstract class AbstractGameFlow implements GameFlow {
    
    @Autowired
    private Player player;
    @Autowired
    private MetadataProvider metadataProvider;
    
    private GameSettings gameSettings;
    
    private List<GameStartedListener> gameStartedListeners = new ArrayList<>();
    private NewRoundListener newRoundListener;
    private UserChangedListener userChangedListener;
    private StopRequestListener stopRequestListener;
    private TimeTickingListener timeTickingListener;
    private SongRevealedListener songRevealedListener;
    private AnswerRequiredListener answerRequiredListener;
    private ScoreChangedListener scoreChangedListener;
    private List<GameDoneListener> gameDoneListeners = new ArrayList<>();
    
    private AnswerRequiredHandlerFactory answerRequiredHandlerFactory 
            = new AnswerRequiredHandlerFactory();
    
    private StopRequestHandlerFactory stopRequestHandlerFactory 
            = new SimpleStopRequestHandlerFactory();
    private ScoreContainerFactory scoreContainerFactory
            = new SimpleScoreContainerFactory();

    @Override
    public void setGameSettings(GameSettings gameSettings) {
        this.gameSettings = gameSettings;
    }

    @Override
    public void gameStarting() {
        for(GameStartedListener gameStartedListener : gameStartedListeners) {
            gameStartedListener.gameStarted();
        }
    }
    
    @Override
    public void donePlaying() {
        this.gameSettings = null;
        
        this.gameStartedListeners.clear();
        this.newRoundListener = null;
        this.userChangedListener = null;
        this.stopRequestListener = null;
        this.timeTickingListener = null;
        this.songRevealedListener = null;
        this.answerRequiredListener = null;
        this.scoreChangedListener = null;
        this.gameDoneListeners.clear();
        
        this.player.stop();
    }

    @Override
    public void addGameStartedListener(GameStartedListener gameStartedListener) {
        this.gameStartedListeners.add(gameStartedListener);
    }

    @Override
    public void setNewRoundListener(NewRoundListener newRoundListener) {
        this.newRoundListener = newRoundListener;
    }

    @Override
    public void setUserChangedListener(UserChangedListener userChangedListener) {
        this.userChangedListener = userChangedListener;
    }

    @Override
    public void setStopRequestListener(StopRequestListener stopRequestListener) {
        this.stopRequestListener = stopRequestListener;
    }

    @Override
    public void setTimeTickingListener(TimeTickingListener timeTickingListener) {
        this.timeTickingListener = timeTickingListener;
    }

    @Override
    public void setSongRevealedListener(SongRevealedListener songRevealedListener) {
        this.songRevealedListener = songRevealedListener;
    }

    @Override
    public void setAnswerRequiredListener(AnswerRequiredListener answerRequiredListener) {
        this.answerRequiredListener = answerRequiredListener;
    }

    @Override
    public void setScoreChangedListener(ScoreChangedListener scoreChangedListener) {
        this.scoreChangedListener = scoreChangedListener;
    }

    @Override
    public void addGameDoneListener(GameDoneListener gameDoneListener) {
        gameDoneListeners.add(gameDoneListener);
    }
    
    protected ScoreContainer createScoreContainer() {
        return scoreContainerFactory.create(scoreChangedListener);
    }

    protected void newRoundEvent(int i, int rounds) {
        newRoundListener.newRound(i, rounds);
    }

    protected void userChangedEvent(String userName) {
        userChangedListener.newUser(userName);
    }

    protected void gameDoneEvent() {
        for(GameDoneListener gameDoneListener : gameDoneListeners) {
            gameDoneListener.gameDone();
        }
    }
    
    protected int waitForStop() {
        StopRequestHandler stopRequestHandler 
                = stopRequestHandlerFactory.create(stopRequestListener, timeTickingListener);
        addGameDoneListener(stopRequestHandler);
        return stopRequestHandler.waitForStop();
    }
    
    protected Answer getAnswer() {
        AnswerRequiredHandler handler
                = answerRequiredHandlerFactory.create(answerRequiredListener, songRevealedListener, 
                                                      metadataProvider, player);
        return handler.getAnswer();
    }

    protected Player getPlayer() {
        return player;
    }

    protected MetadataProvider getMetadataProvider() {
        return metadataProvider;
    }

    GameSettings getGameSettings() {
        return gameSettings;
    }

    List<GameStartedListener> getGameStartedListeners() {
        return gameStartedListeners;
    }

    NewRoundListener getNewRoundListener() {
        return newRoundListener;
    }

    UserChangedListener getUserChangedListener() {
        return userChangedListener;
    }

    StopRequestListener getStopRequestListener() {
        return stopRequestListener;
    }

    TimeTickingListener getTimeTickingListener() {
        return timeTickingListener;
    }

    SongRevealedListener getSongRevealedListener() {
        return songRevealedListener;
    }

    AnswerRequiredListener getAnswerRequiredListener() {
        return answerRequiredListener;
    }

    ScoreChangedListener getScoreChangedListener() {
        return scoreChangedListener;
    }

    List<GameDoneListener> getGameDoneListeners() {
        return gameDoneListeners;
    }

    StopRequestHandlerFactory getStopRequestHandlerFactory() {
        return stopRequestHandlerFactory;
    }

    ScoreContainerFactory getScoreContainerFactory() {
        return scoreContainerFactory;
    }

    void setStopRequestHandlerFactory(StopRequestHandlerFactory stopRequestHandlerFactory) {
        this.stopRequestHandlerFactory = stopRequestHandlerFactory;
    }

    void setAnswerRequiredHandlerFactory(AnswerRequiredHandlerFactory answerRequiredHandlerFactory) {
        this.answerRequiredHandlerFactory = answerRequiredHandlerFactory;
    }

    void setScoreContainerFactory(ScoreContainerFactory scoreContainerFactory) {
        this.scoreContainerFactory = scoreContainerFactory;
    }

    void setPlayer(Player player) {
        this.player = player;
    }

    void setMetadataProvider(MetadataProvider metadataProvider) {
        this.metadataProvider = metadataProvider;
    }

}
